package cz.cuni.mff.abacs.burglar.visual;

import com.aem.sticky.StickyListener;
import com.aem.sticky.button.Button;
import com.aem.sticky.button.TextButton;
import com.aem.sticky.button.events.ClickListener;
import cz.cuni.mff.abacs.burglar.visual.play_state.PlayState;
import java.io.File;
import java.util.*;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.Sound;
import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.state.StateBasedGame;


/**
 * Game state enabling to select a level.
 * 
 * @author abacs
 *
 */
public class LevelSelectionState extends BasicGameState {
	
	
	// -------------------------------------------------------------------------
	
	/** File extension of the level files. */
	private static final String MAP_EXTENSION = ".xml";
	
	/** Width of the buttons in pixels. */
	public static final int BUTTON_WIDTH  = 100;
	/** Height of the buttons in pixels. */
	public static final int BUTTON_HEIGHT = 21;
	
	protected static String STR_BACK = "Back";
	
	/** Button sound. */
	protected static String SUBPATH_CLICK_SOUND = "click.ogg";	
	
	
	// -------------------------------------------------------------------------
	
	/** State identifier. */
	private final int _stateID;
	
	protected StickyListener _buttonListener;
	
	/** Buttons representing the levels. */
	protected List<Button> _levelButtons = new LinkedList<Button>();
	
	/** Remembers which map to open on each button.  */
	protected Map<Button, String> _buttonsToFiles = 
		new LinkedHashMap<Button, String>();
	
	/** Back to the MenuState button. */
	protected Button _backButton;
	
	/** Parent object. */
	protected GameContainer _container = null;
	
	/** Parent object. */
	protected StateBasedGame _stateBasedGame = null;
	
	
	// -------------------------------------------------------------------------
	// constructors:
	
	
	/** 
	 * 
	 * 
	 * @param stateId
	 */
	public LevelSelectionState(int stateId) {
		this._stateID = stateId;
	}
	
	
	// -------------------------------------------------------------------------
	// BasigGameState:
	
	
	@Override
	public int getID() {
		return this._stateID;
	}
	
	
	/** 
	 * Initialize any needed data before the menu loop.
	 * 
	 * @param container 
	 * @param game 
	 * @throws SlickExpression
	 */
	@Override
	public void init(GameContainer container, StateBasedGame game)
		throws SlickException {
		
		this._stateBasedGame = game;
		this._container = container;
		
		Sound buttonSound = new Sound(VisualBurglar.PATH_SOUNDS + SUBPATH_CLICK_SOUND);
		
		// buttons:
		this._buttonListener = new StickyListener();
		
		this.createLevelButtons(container, buttonSound);
		this.createBackButton(container, buttonSound);
	}
	
	
	/**
	 * Adds listeners.
	 */
	@Override
	public void enter(GameContainer container, StateBasedGame game) throws SlickException {
		super.enter(container, game);
		container.getInput().addListener(this._buttonListener);
		System.out.println("Level selection state entered");
	}
	
	
	/**
	 * Removes all listeners.
	 */
	@Override
	public void leave(GameContainer container, StateBasedGame game) throws SlickException {
		super.leave(container, game);
		container.getInput().removeListener(_buttonListener);
		System.out.println("Level selection state left");
	}
	
	
	/**
	 * Called during the game to update the logic in our world,
	 * within this method we obtain the user input,
	 * calculate the world response to the input, do the calculation.
	 * 
	 * @param container
	 * @param game
	 * @param delta
	 * @throws SlickExpression
	 */
	@Override
	public void update(GameContainer container, StateBasedGame game, int delta)
		throws SlickException {
		
		for(Button button : this._levelButtons)
			button.update(container, delta);
		this._backButton.update(container, delta); 
	}
	
	
	/**
	 *  Allows to draw the menu.
	 *  
	 * @param container
	 * @param game
	 * @param delta
	 * @throws SlickExpression
	 */
	@Override
	public void render(
			GameContainer container,
			StateBasedGame game,
			Graphics graphics
	) throws SlickException {
		// Draw menu
		for(Button button : this._levelButtons)
			button.render(container, graphics);
		this._backButton.render(container, graphics);
	}
	
	
	// -------------------------------------------------------------------------
	// buttons:
	
	
	/** Returns with the names of the levels. */
	private List<String> getLevelNames() {
		List<String> result = new ArrayList<String>();
		
		File dir = new File(VisualBurglar.PATH_MAPS);
		final String[] chld = dir.list();
		
		if(chld == null){
			return result;
		}
		
		int extension_length = MAP_EXTENSION.length();
		for(String str : chld){
			if(str.endsWith(MAP_EXTENSION)){
				result.add(str.substring(0, str.length() - extension_length));
			}
		}
		
		// sort the names:
		Collections.sort(result);
		
		return result;
	}
	
	
	/** 
	 * Generates the buttons.
	 * 
	 * @param container
	 * @param buttonSound
	 * @throws SlickException
	 */
	protected void createLevelButtons(
			final GameContainer container,
			Sound buttonSound
	) throws SlickException {
		
		float x = 10;
		float y = 10;
		
		List<String> levelNames = this.getLevelNames();
		
		for(int i = 0; i < levelNames.size(); i++){
			
			TextButton button = new TextButton(
					x,
					y + i * (BUTTON_HEIGHT + 4),
					levelNames.get(i),
					buttonSound
			);
			
			this._buttonListener.add(button);
			this._levelButtons.add(button);
			this._buttonsToFiles.put(button, levelNames.get(i));
			
			button.addListener(new ClickListener() {
				
				@Override
				public void onClick(
						com.aem.sticky.button.Button arg0,
						float arg1,
						float arg2
				) {
					// load the map:
					PlayState playState = 
						(PlayState)_stateBasedGame.getState(VisualBurglar.STATE_PLAY);
					playState.load(
							VisualBurglar.PATH_MAPS +
							_buttonsToFiles.get(arg0) +
							MAP_EXTENSION);
					// enters the new game state:
					_stateBasedGame.enterState(VisualBurglar.STATE_PLAY);	
				}
				
				/** Does nothing */
				@Override
				public void onDoubleClick(Button arg0, float arg1, float arg2) { }
				
				/** Does nothing */
				@Override
				public void onRightClick(Button arg0, float arg1, float arg2) { }
			});
		}
		
	}
	
			
	/**
	 * Back button.
	 * 
	 * @param container
	 * @param buttonSound
	 * @throws SlickException
	 */
	protected void createBackButton(GameContainer container, Sound buttonSound)
		throws SlickException {
		
		TextButton button = new TextButton(
				10,
				10 + (this._levelButtons.size()) * (BUTTON_HEIGHT + 2),
				STR_BACK,
				buttonSound
		);
		
		this._buttonListener.add(button);
		this._backButton = button;
		
		button.addListener(new ClickListener() {
			
			@Override
			public void onClick(Button arg0, float arg1, float arg2) {
				// enters the menu state:
				_stateBasedGame.enterState(VisualBurglar.STATE_MENU);	
			}
			
			/** Does nothing */
			@Override
			public void onDoubleClick(Button arg0, float arg1, float arg2) { }
			
			/** Does nothing */
			@Override
			public void onRightClick(Button arg0, float arg1, float arg2) { }
		});
		
	}
	
	
}
